#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/in.h>

#include "socket.c"
#include "ssl/ssl.c"
#include "main.h"

#define SERVER_ADDR "0.0.0.0"
#define SERVER_PORT 8000

#define BUF_SIZE 65536

int handle_connack(int fd, struct sockaddr_in *sa, int state){
	uint8_t sbuf[BUF_SIZE];
	//start respond msg
	p_connack *h = (p_connack *)&sbuf;
	size_t slen = sizeof(p_connack);

	h->state = state;

	//gen random number
	gen_random_bytes(h->random, NUM_ECC_DIGITS);
	//gen sign
	//uint8_t r[NUM_ECC_DIGITS], s[NUM_ECC_DIGITS];
	//ecdsa_sign(r, s, ser_pri_key, random, random);

	//hex_print(r, NUM_ECC_DIGITS);
	//hex_print(s, NUM_ECC_DIGITS);

	//int ret = ecdsa_verify(&ser_pub_key, random, r, s);
	//printf("verify %d\n", ret);

	printf("sendto \n");
	socklen_t sa_len = sizeof(struct sockaddr_in);
	int ret = sendto(fd, sbuf, slen, 0, (struct sockaddr *)sa, sa_len);
	printf("ret:%d\n", ret);
	return 0;
}

int handle_connect(int fd, uint8_t *rbuf, size_t rlen, struct sockaddr_in *sa){
	//check the connect packet has padding
	if(rlen <= sizeof(p_head) + 1) return -1;

	p_connect *h = (p_connect *)rbuf;
	rbuf += sizeof(p_connect);
	rlen -= sizeof(p_connect);

	switch(h->ver){
		case 0:
			break;
		default:
			printf("unknow protocol version\n");
			return UNKNOW_PROTOCOL;
			break;
	}

	//gen share serret
	uint8_t secret[NUM_ECC_DIGITS];
	if(0 == ecdh_shared_secret(secret, &h->pub_key, ser_pri_key, h->random)) return SECRET_INVAILD;
	//create a client
	client_t *client = malloc(sizeof(client_t));
	if(NULL == client) return SERVER_ERROR;
	//save expansion key and random number
	aes_set_secret(secret, client->w);
	memcpy(client->random, h->random, NUM_ECC_DIGITS);
	//decrypt payload
	aes_ctr_cipher(rbuf, rlen, client->w, client->random);

	//...

	//show messages
	//char sbuf[BUF_SIZE];
	//bzero(sbuf, BUF_SIZE);
	//memcpy(sbuf, rbuf, rlen);
	//printf("%d %s\n", rlen, sbuf);

	return SUCCESS;
}

int packet_handle(int fd, uint8_t *rbuf, size_t rlen, struct sockaddr_in *sa){
	//check length
	if(rlen < sizeof(p_head)) return -1;
	//mount to struct
	p_head *h = (p_head *)rbuf;
	rbuf += sizeof(p_head);
	rlen -= sizeof(p_head);
	
	//printf("len=%d\n", rlen);

	int ret = 0;
	switch(h->type){
		case CONNECT:
			ret = handle_connect(fd, rbuf, rlen, sa);
			handle_connack(fd, sa, ret);
			break;
		case CONNACK:
			break;
		default:
			printf("Unknow packet type\n");
			break;
	}

	return 0;
}


void serivce_start(char *addr, int port){
	int fd = socket_init(addr, port);

	int rlen;
	uint8_t rbuf[BUF_SIZE];

	struct sockaddr_in sa;
	socklen_t sa_len = sizeof(sa);

	while(1){
		rlen = recvfrom(fd, rbuf, BUF_SIZE, 0, (struct sockaddr *)&sa, &sa_len);
		if(rlen >= 0){
			packet_handle(fd, rbuf, rlen, &sa);
		}else{
			//timeout
			printf("%lld\n", iclock());
		}
	}

	close(fd);
}

int main(){
	serivce_start(SERVER_ADDR, SERVER_PORT);	
	return 0;
}

